#pragma once
#include <cstdint>

//#include <type_traits>

#include "select.h"

namespace tools{

    template<class T> struct ParamComplete
    {
        #ifdef _MSC_VER
            static T & getT();
            static char (& pass(T))[2];
            static char pass(...);
            enum { value = sizeof(pass(getT()))==2 };
        #else
            typedef char (&No)[1]; typedef char (&Yes)[2];
            template<class U, size_t N = sizeof(U) >struct Helper;
            template<class U>static Yes HelpMe( Helper<U>* p);
            template<class U>static No HelpMe(...);
            enum { value = sizeof(HelpMe<T>(0)) == sizeof(Yes) };
        #endif
    };

    struct ParamNoComplete
    {
        enum { value = 0 };
    };


    template<class T> struct is_complete
    {
        enum { value = ParamComplete<T>::value };
    };
    
    template< class T1, class T2, template<class T1, class T2> class T >
    struct is_complete< T<T1, T2> >
    {
        typedef T<T1, T2> me;
        enum { complete_param =
               is_complete<T1>::value &&
               is_complete<T2>::value
             };

        typedef typename Select<complete_param, ParamComplete<me>, ParamNoComplete >::Result type;
        enum { value = type::value };
    };

    template< class T1, class T2,class T3, template<class T1, class T2, class T3> class T >
    struct is_complete< T<T1, T2,T3> >
    {
        typedef T<T1, T2, T3> me;
        enum { complete_param =
               is_complete<T1>::value &&
               is_complete<T2>::value &&
               is_complete<T3>::value
             };

        typedef typename Select<complete_param, ParamComplete<me>, ParamNoComplete >::Result type;
        enum { value = type::value };
    };


}//namespace tools
